import static org.junit.Assert.*;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;

import org.junit.Test;

// IMPORTANT!!! Backup your current save-file as this system test will overwrite it
public class SystemTest {

	@Test
	public void addTest() {

		ArrayList<Task> correctData = getCloneOf(Storage.loadedData);
		
		// Run add Command
		MainUi.processUserInput("add new Task /st 13/08/1992");
		
		// Manually add to correct Data
		Task newTask = new Task();
		newTask.id = getNextId(correctData);
		newTask.title = "new Task";
		try {
			newTask.startTime = new SimpleDateFormat("dd/MM/yyyy")
					.parse("13/08/1992");
		} catch (ParseException e) {
			e.printStackTrace();
		}
		correctData.add(newTask);

		// Compare ArrayLists
		assertTrue(isSameArrayList(correctData, Storage.loadedData));

	}

	@Test
	public void editTest() {

		// If no task available for edit, force one in for test
		if (Storage.loadedData.isEmpty()) {
			Task newTask = new Task();
			newTask.id = 1;
			newTask.title = "Task To Edit";
			Storage.loadedData.add(newTask);
			Storage.saveData();
		}
		
		ArrayList<Task> correctData = getCloneOf(Storage.loadedData);

		int highestId = getNextId(Storage.loadedData) - 1;
		
		// Run edit Command
		MainUi.processUserInput("edit /id " + highestId + " /pl new Place");
		
		// Manually edit to correctData
		Task taskToEdit = locateTask(highestId, correctData);
		taskToEdit.place = "new Place";

		// Compare ArrayLists
		assertTrue(isSameArrayList(correctData, Storage.loadedData));

	}

	@Test
	public void deleteTest() {

		// If no task available for delete, force one in for test
		if (Storage.loadedData.isEmpty()) {
			Task newTask = new Task();
			newTask.id = 1;
			newTask.title = "Task To Delete";
			Storage.loadedData.add(newTask);
			Storage.saveData();
		}
		ArrayList<Task> correctData = getCloneOf(Storage.loadedData);

		int highestId = getNextId(Storage.loadedData) - 1;

		// Run Delete Command
		MainUi.processUserInput("delete /id " + highestId);
		
		// Manually Delete From Correct Data
		Task taskToDelete = locateTask(highestId, correctData);
		for (int i = 0; i < correctData.size(); i++) {
			if (isSameExactTask(taskToDelete, correctData.get(i))) {
				correctData.remove(i);
			}
		}

		assertTrue(isSameArrayList(correctData, Storage.loadedData));

	}
	
	@Test
	public void DoneTest() {

		// If no task available for done-marking, force one in for test
		if (Storage.loadedData.isEmpty()) {
			Task newTask = new Task();
			newTask.id = 1;
			newTask.title = "Task To Mark Done";
			Storage.loadedData.add(newTask);
			Storage.saveData();
		}
		ArrayList<Task> correctData = getCloneOf(Storage.loadedData);

		int highestId = getNextId(Storage.loadedData) - 1;
		
		// Run Done Command
		MainUi.processUserInput("done /id " + highestId);
		
		// Manually Mark Task in Correct Data as Done
		Task taskToMark = locateTask(highestId, correctData);
		taskToMark.isDone = true;

		assertTrue(isSameArrayList(correctData, Storage.loadedData));

	}

	// Arraylist's .clone() doesn't clone the elements (the different lists will
	// refer to the same tasks) so we will create clones manually with the help
	// of the .clone() we coded for Task
	private ArrayList<Task> getCloneOf(ArrayList<Task> loadedData) {
		ArrayList<Task> clonedCopy = new ArrayList<Task>();
		for (Task task : loadedData) {
			clonedCopy.add(task.clone());
		}
		return clonedCopy;
	}

	private Task locateTask(int id, ArrayList<Task> listOfTask) {
		for (Task task : listOfTask) {
			if (task.id == id) {
				return task;
			}
		}
		return null;
	}

	private boolean isSameArrayList(ArrayList<Task> arrayList1,
			ArrayList<Task> arrayList2) {
		if (arrayList1.size() != arrayList2.size()) {
			return false;
		}
		for (int i = 0; i < arrayList1.size(); i++) {
			if (!isSameExactTask(arrayList1.get(i), arrayList2.get(i))) {
				return false;
			}
		}
		return true;
	}

	private int getNextId(ArrayList<Task> currentData) {
		int nextId = 1;
		for (Task task : currentData) {
			if (task.id >= nextId) {
				nextId = task.id + 1;
			}
		}
		return nextId;
	}

	private boolean isSameExactTask(Task taskToMatch, Task taskToCheck) {
		if (taskToMatch == null) {
			if (taskToCheck != null) {
				return false;
			} else {
				return true;
			}
		} else {
			if (taskToCheck == null) {
				return false;
			}
		}

		if (taskToMatch.id != taskToCheck.id) {
			return false;
		}

		if (taskToMatch.title != Task.EMPTY_STRING) {
			if (taskToCheck.title == Task.EMPTY_STRING) {
				return false;
			}
			if (!taskToMatch.title.equals(taskToCheck.title)) {
				return false;
			}
		} else {
			if (taskToCheck.title != Task.EMPTY_STRING) {
				return false;
			}
		}

		if (taskToMatch.place != Task.EMPTY_STRING) {
			if (taskToCheck.place == Task.EMPTY_STRING) {
				return false;
			}
			if (!taskToMatch.place.equals(taskToCheck.place)) {
				return false;
			}
		} else {
			if (taskToCheck.place != Task.EMPTY_STRING) {
				return false;
			}
		}

		if (taskToMatch.description != Task.EMPTY_STRING) {
			if (taskToCheck.description == Task.EMPTY_STRING) {
				return false;
			}
			if (!taskToMatch.description.equals(taskToCheck.description)) {
				return false;
			}
		} else {
			if (taskToCheck.description != Task.EMPTY_STRING) {
				return false;
			}
		}

		if (taskToMatch.project != Task.EMPTY_STRING) {
			if (taskToCheck.project == Task.EMPTY_STRING) {
				return false;
			}
			if (!taskToMatch.project.equals(taskToCheck.project)) {
				return false;
			}
		} else {
			if (taskToCheck.project != Task.EMPTY_STRING) {
				return false;
			}
		}

		if (taskToMatch.startTime != Task.EMPTY_TIME) {
			if (taskToCheck.startTime == Task.EMPTY_TIME) {
				return false;
			}
			if (!taskToMatch.startTime.equals(taskToCheck.startTime)) {
				return false;
			}
		} else {
			if (taskToCheck.startTime != Task.EMPTY_TIME) {
				return false;
			}
		}

		if (taskToMatch.endTime != Task.EMPTY_TIME) {
			if (taskToCheck.endTime == Task.EMPTY_TIME) {
				return false;
			}
			if (!taskToMatch.endTime.equals(taskToCheck.endTime)) {
				return false;
			}
		} else {
			if (taskToCheck.endTime != Task.EMPTY_TIME) {
				return false;
			}
		}
		
		if(taskToMatch.isDone != taskToCheck.isDone){
			return false;
		}

		return true;
	}

}
